const fs = require('fs');
const fsExtra = require('fs-extra');
const path = require('path');
const { spawn } = require('child_process');
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
const ffprobePath = require('@ffprobe-installer/ffprobe').path;
const Database = require('better-sqlite3');
const { EventEmitter } = require('events');

// 设置 ffmpeg 和 ffprobe 路径
ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg.setFfprobePath(ffprobePath);

class YouTubeDownloader extends EventEmitter {
  constructor(downloadDir = './downloads') {
    super();
    this.downloadDir = downloadDir;
    this.ensureDownloadDir();
    
    // 数据库初始化
    this.dbPath = path.join(this.downloadDir, 'file_cache.db');
    this.db = new Database(this.dbPath);
    this.initDatabase();
    
    // 缓存配置
    this.memoryCache = new Map();
    this.cacheExpiry = 5 * 60 * 1000; // 5分钟缓存
    this.lastFullScan = 0;
    this.fullScanInterval = 10 * 60 * 1000; // 10分钟全量扫描间隔
    this.incrementalScanInterval = 30 * 1000; // 30秒增量扫描间隔
    
    // 后台扫描配置
    this.backgroundScanEnabled = true;
    this.backgroundScanInterval = 30 * 1000; // 30秒增量扫描
    this.isScanning = false;
    this.scanQueue = new Set();
    this.lastScanTime = null;
    this.currentScanType = null;
    this.scanStartTime = null;
    
    // 启动后台扫描
    this.startBackgroundScan();
    
    // 监听文件系统变化
    this.setupFileWatcher();
  }

  // 初始化数据库
  initDatabase() {
    try {
      // 创建文件信息表
      this.db.exec(`
        CREATE TABLE IF NOT EXISTS files (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          file_path TEXT UNIQUE NOT NULL,
          file_name TEXT NOT NULL,
          file_size INTEGER NOT NULL,
          created_time INTEGER NOT NULL,
          modified_time INTEGER NOT NULL,
          date_dir TEXT NOT NULL,
          title_dir TEXT NOT NULL,
          relative_path TEXT NOT NULL,
          is_video INTEGER DEFAULT 0,
          video_duration REAL,
          video_duration_cached INTEGER DEFAULT 0,
          video_width INTEGER,
          video_height INTEGER,
          video_bitrate INTEGER,
          video_orientation TEXT,
          video_info_cached INTEGER DEFAULT 0,
          scan_time INTEGER NOT NULL,
          file_hash TEXT
        )
      `);

      // 检查并添加新字段（用于数据库升级）
      try {
        this.db.exec(`ALTER TABLE files ADD COLUMN video_width INTEGER`);
      } catch (e) { /* 字段已存在 */ }
      try {
        this.db.exec(`ALTER TABLE files ADD COLUMN video_height INTEGER`);
      } catch (e) { /* 字段已存在 */ }
      try {
        this.db.exec(`ALTER TABLE files ADD COLUMN video_bitrate INTEGER`);
      } catch (e) { /* 字段已存在 */ }
      try {
        this.db.exec(`ALTER TABLE files ADD COLUMN video_orientation TEXT`);
      } catch (e) { /* 字段已存在 */ }
      try {
        this.db.exec(`ALTER TABLE files ADD COLUMN video_info_cached INTEGER DEFAULT 0`);
      } catch (e) { /* 字段已存在 */ }

      // 创建文件表索引
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_files_path ON files(file_path)`);
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_files_date_dir ON files(date_dir)`);
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_files_title_dir ON files(title_dir)`);
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_files_is_video ON files(is_video)`);
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_files_scan_time ON files(scan_time)`);

      // 创建扫描历史表
      this.db.exec(`
        CREATE TABLE IF NOT EXISTS scan_history (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          scan_type TEXT NOT NULL,
          start_time INTEGER NOT NULL,
          end_time INTEGER,
          duration_ms INTEGER,
          files_scanned INTEGER DEFAULT 0,
          files_added INTEGER DEFAULT 0,
          files_updated INTEGER DEFAULT 0,
          files_removed INTEGER DEFAULT 0,
          error_message TEXT
        )
      `);

      // 创建搜索关系表
      this.db.exec(`
        CREATE TABLE IF NOT EXISTS search_relations (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          original_keyword TEXT NOT NULL,
          sanitized_keyword TEXT NOT NULL,
          video_title TEXT NOT NULL,
          file_path TEXT NOT NULL,
          created_time INTEGER NOT NULL
        )
      `);

      // 创建搜索关系表索引
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_search_original ON search_relations(original_keyword)`);
      this.db.exec(`CREATE INDEX IF NOT EXISTS idx_search_sanitized ON search_relations(sanitized_keyword)`);

      console.log('数据库初始化完成');
    } catch (error) {
      console.error('数据库初始化失败:', error.message);
    }
  }

  // 启动后台扫描
  startBackgroundScan() {
    if (!this.backgroundScanEnabled) return;

    // 立即执行一次全量扫描
    setTimeout(() => {
      this.performFullScan();
    }, 1000);

    // 定期增量扫描
    this.backgroundScanTimer = setInterval(() => {
      if (!this.isScanning) {
        this.performIncrementalScan();
      }
    }, this.backgroundScanInterval);

    // 定期全量扫描
    this.fullScanTimer = setInterval(() => {
      if (!this.isScanning) {
        this.performFullScan();
      }
    }, this.fullScanInterval);
  }

  // 停止后台扫描
  stopBackgroundScan() {
    this.backgroundScanEnabled = false;
    if (this.backgroundScanTimer) {
      clearInterval(this.backgroundScanTimer);
    }
    if (this.fullScanTimer) {
      clearInterval(this.fullScanTimer);
    }
  }

  // 设置文件系统监听
  setupFileWatcher() {
    try {
      if (fsExtra.existsSync(this.downloadDir)) {
        // 简单的文件变化检测，避免过于复杂的监听
        this.watchTimer = setInterval(() => {
          if (this.scanQueue.size > 0 && !this.isScanning) {
            this.performIncrementalScan();
          }
        }, 5000);
      }
    } catch (error) {
      console.warn('文件监听设置失败:', error.message);
    }
  }

  // 执行全量扫描
  async performFullScan() {
    if (this.isScanning) return;
    
    this.isScanning = true;
    this.currentScanType = 'full';
    this.scanStartTime = Date.now();
    const startTime = this.scanStartTime;
    const scanId = this.recordScanStart('full');
    
    try {
      console.log('开始全量文件扫描...');
      
      const stats = {
        filesScanned: 0,
        filesAdded: 0,
        filesUpdated: 0,
        filesRemoved: 0
      };

      // 获取数据库中的所有文件
      const dbFiles = new Map();
      const dbFileRows = this.db.prepare('SELECT * FROM files').all();
      dbFileRows.forEach(row => {
        dbFiles.set(row.file_path, row);
      });

      // 扫描文件系统
      const currentFiles = new Map();
      await this.scanDirectory(this.downloadDir, currentFiles, stats);

      // 标记已删除的文件
      for (const [filePath, dbFile] of dbFiles) {
        if (!currentFiles.has(filePath)) {
          this.db.prepare('DELETE FROM files WHERE file_path = ?').run(filePath);
          stats.filesRemoved++;
        }
      }

      this.lastFullScan = Date.now();
      this.lastScanTime = this.lastFullScan;
      this.recordScanEnd(scanId, stats);
      
      // 清除内存缓存，强制重新加载
      this.memoryCache.clear();
      
      const endTime = Date.now();
      console.log(`全量扫描完成，耗时: ${endTime - startTime}ms`, stats);
      
      this.emit('scanComplete', { type: 'full', stats, duration: endTime - startTime });
      
    } catch (error) {
      console.error('全量扫描失败:', error.message);
      this.recordScanError(scanId, error.message);
    } finally {
      this.isScanning = false;
      this.currentScanType = null;
      this.scanStartTime = null;
    }
  }

  // 执行增量扫描
  async performIncrementalScan() {
    if (this.isScanning) return;
    
    this.isScanning = true;
    this.currentScanType = 'incremental';
    this.scanStartTime = Date.now();
    const startTime = this.scanStartTime;
    const scanId = this.recordScanStart('incremental');
    
    try {
      const stats = {
        filesScanned: 0,
        filesAdded: 0,
        filesUpdated: 0,
        filesRemoved: 0
      };

      // 只扫描队列中的目录或最近修改的目录
      const dirsToScan = this.scanQueue.size > 0 ? Array.from(this.scanQueue) : [this.downloadDir];
      this.scanQueue.clear();

      for (const dir of dirsToScan) {
        if (fsExtra.existsSync(dir)) {
          const currentFiles = new Map();
          await this.scanDirectory(dir, currentFiles, stats, true); // 增量模式
        }
      }

      this.lastScanTime = Date.now();
      this.recordScanEnd(scanId, stats);
      
      if (stats.filesAdded > 0 || stats.filesUpdated > 0 || stats.filesRemoved > 0) {
        // 只有在有变化时才清除缓存
        this.memoryCache.delete('files');
        this.memoryCache.delete('filesByDate');
        this.memoryCache.delete('directoryStructure');
        
        const endTime = Date.now();
        console.log(`增量扫描完成，耗时: ${endTime - startTime}ms`, stats);
        this.emit('scanComplete', { type: 'incremental', stats, duration: endTime - startTime });
      }
      
    } catch (error) {
      console.error('增量扫描失败:', error.message);
      this.recordScanError(scanId, error.message);
    } finally {
      this.isScanning = false;
      this.currentScanType = null;
      this.scanStartTime = null;
    }
  }

  // 扫描目录
  async scanDirectory(dirPath, currentFiles, stats, incremental = false) {
    try {
      if (!fsExtra.existsSync(dirPath)) return;

      const items = await fsExtra.readdir(dirPath);
      
      for (const item of items) {
        const itemPath = path.join(dirPath, item);
        const itemStat = await fsExtra.stat(itemPath);
        
        if (itemStat.isDirectory()) {
          // 递归扫描子目录
          await this.scanDirectory(itemPath, currentFiles, stats, incremental);
        } else if (itemStat.isFile()) {
          await this.processFile(itemPath, itemStat, currentFiles, stats, incremental);
        }
      }
    } catch (error) {
      console.warn(`扫描目录失败: ${dirPath}`, error.message);
    }
  }

  // 处理单个文件
  async processFile(filePath, fileStat, currentFiles, stats, incremental = false) {
    try {
      stats.filesScanned++;
      currentFiles.set(filePath, true);

      const relativePath = path.relative(this.downloadDir, filePath);
      const pathParts = relativePath.split(path.sep);
      
      if (pathParts.length < 2) return; // 跳过根目录文件

      const dateDir = pathParts[0];
      const titleDir = pathParts[1];
      const fileName = path.basename(filePath);
      
      const modifiedTime = fileStat.mtime.getTime();
      const createdTime = fileStat.birthtime.getTime();
      const fileSize = fileStat.size;
      const isVideo = this.isVideoFile(fileName) ? 1 : 0;

      // 检查数据库中是否存在
      const existingFile = this.db.prepare('SELECT * FROM files WHERE file_path = ?').get(filePath);
      
      if (existingFile) {
        // 检查是否需要更新
        if (existingFile.modified_time !== modifiedTime || existingFile.file_size !== fileSize) {
          // 文件已修改，更新记录
          this.db.prepare(`
            UPDATE files SET 
              file_size = ?, modified_time = ?, scan_time = ?,
              video_duration_cached = 0
            WHERE file_path = ?
          `).run(fileSize, modifiedTime, Date.now(), filePath);
          
          stats.filesUpdated++;
          
          // 如果是视频文件，重新获取时长
          if (isVideo) {
            this.queueVideoDurationUpdate(filePath);
          }
        }
      } else {
        // 新文件，插入记录
        this.db.prepare(`
          INSERT INTO files (
            file_path, file_name, file_size, created_time, modified_time,
            date_dir, title_dir, relative_path, is_video, scan_time
          ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        `).run(
          filePath, fileName, fileSize, createdTime, modifiedTime,
          dateDir, titleDir, relativePath, isVideo, Date.now()
        );
        
        stats.filesAdded++;
        
        // 如果是视频文件，异步获取时长
        if (isVideo) {
          this.queueVideoDurationUpdate(filePath);
        }
      }
    } catch (error) {
      console.warn(`处理文件失败: ${filePath}`, error.message);
    }
  }

  // 队列化视频信息更新（包含时长和其他信息）
  queueVideoInfoUpdate(filePath) {
    // 使用setTimeout避免阻塞主扫描流程
    setTimeout(async () => {
      try {
        // 使用VideoInfoHelper获取完整的视频信息
        const VideoInfoHelper = require('./videoInfoHelper');
        const videoInfoHelper = new VideoInfoHelper(this.downloadDir);
        
        const videoInfo = await videoInfoHelper.getVideoInfo(filePath);
        
        if (videoInfo && videoInfo.duration !== null) {
          this.db.prepare(`
            UPDATE files SET 
              video_duration = ?, 
              video_width = ?, 
              video_height = ?, 
              video_bitrate = ?, 
              video_orientation = ?,
              video_duration_cached = 1,
              video_info_cached = 1
            WHERE file_path = ?
          `).run(
            videoInfo.duration, 
            videoInfo.width, 
            videoInfo.height, 
            videoInfo.bitrate, 
            videoInfo.orientation,
            filePath
          );
        } else {
          // 标记为已尝试获取但失败
          this.db.prepare(`
            UPDATE files SET video_duration_cached = -1, video_info_cached = -1
            WHERE file_path = ?
          `).run(filePath);
        }
      } catch (error) {
        console.warn(`获取视频信息失败: ${filePath}`, error.message);
        this.db.prepare(`
          UPDATE files SET video_duration_cached = -1, video_info_cached = -1
          WHERE file_path = ?
        `).run(filePath);
      }
    }, Math.random() * 1000); // 随机延迟避免同时处理太多文件
  }

  // 保持向后兼容的时长更新方法
  queueVideoDurationUpdate(filePath) {
    this.queueVideoInfoUpdate(filePath);
  }

  // 带超时的视频时长获取
  async getVideoDurationWithTimeout(filePath, timeout = 5000) {
    return new Promise((resolve) => {
      const timer = setTimeout(() => {
        resolve(null);
      }, timeout);

      ffmpeg.ffprobe(filePath, (err, metadata) => {
        clearTimeout(timer);
        
        if (err) {
          resolve(null);
          return;
        }
        
        try {
          const duration = metadata.format.duration;
          if (duration && !isNaN(duration)) {
            resolve(parseFloat(duration));
          } else {
            resolve(null);
          }
        } catch (error) {
          resolve(null);
        }
      });
    });
  }

  // 记录扫描开始
  recordScanStart(scanType) {
    const result = this.db.prepare(`
      INSERT INTO scan_history (scan_type, start_time) VALUES (?, ?)
    `).run(scanType, Date.now());
    return result.lastInsertRowid;
  }

  // 记录扫描结束
  recordScanEnd(scanId, stats) {
    const endTime = Date.now();
    
    // 获取开始时间以计算持续时间
    const scanRecord = this.db.prepare('SELECT start_time FROM scan_history WHERE id = ?').get(scanId);
    const durationMs = scanRecord ? endTime - scanRecord.start_time : 0;
    
    this.db.prepare(`
      UPDATE scan_history SET 
        end_time = ?, duration_ms = ?, files_scanned = ?, files_added = ?, 
        files_updated = ?, files_removed = ?
      WHERE id = ?
    `).run(
      endTime, durationMs, stats.filesScanned, stats.filesAdded,
      stats.filesUpdated, stats.filesRemoved, scanId
    );
  }

  // 记录扫描错误
  recordScanError(scanId, errorMessage) {
    this.db.prepare(`
      UPDATE scan_history SET end_time = ?, error_message = ? WHERE id = ?
    `).run(Date.now(), errorMessage, scanId);
  }

  // 获取下载的文件列表（优化版本）
  async getDownloadedFiles() {
    try {
      // 检查内存缓存
      const cacheKey = 'files';
      const cached = this.memoryCache.get(cacheKey);
      if (cached && (Date.now() - cached.timestamp) < this.cacheExpiry) {
        console.log('使用内存缓存的文件列表');
        return cached.data;
      }

      console.log('从数据库获取文件列表...');
      const startTime = Date.now();

      // 从数据库获取文件列表
      const files = this.db.prepare(`
        SELECT 
          file_name as name,
          file_path as path,
          file_size as size,
          created_time as created,
          date_dir as dateDir,
          title_dir as titleDir,
          relative_path as relativePath,
          video_duration as duration,
          video_width as width,
          video_height as height,
          video_bitrate as bitrate,
          video_orientation as orientation,
          is_video as isVideo
        FROM files 
        ORDER BY created_time DESC
      `).all();

      // 转换数据格式
      const formattedFiles = files.map(file => ({
        ...file,
        created: new Date(file.created),
        size: parseInt(file.size),
        duration: file.duration || null,
        width: file.width || null,
        height: file.height || null,
        bitrate: file.bitrate || null,
        orientation: file.orientation || null,
        isVideo: Boolean(file.isVideo)
      }));

      // 更新内存缓存
      this.memoryCache.set(cacheKey, {
        data: formattedFiles,
        timestamp: Date.now()
      });

      const endTime = Date.now();
      console.log(`文件列表获取完成，耗时: ${endTime - startTime}ms，共 ${formattedFiles.length} 个文件`);

      return formattedFiles;
    } catch (error) {
      console.error('获取文件列表失败:', error.message);
      throw new Error('获取下载文件列表失败: ' + error.message);
    }
  }

  // 按日期获取文件列表（优化版本）
  async getDownloadedFilesByDate() {
    try {
      // 检查内存缓存
      const cacheKey = 'filesByDate';
      const cached = this.memoryCache.get(cacheKey);
      if (cached && (Date.now() - cached.timestamp) < this.cacheExpiry) {
        console.log('使用内存缓存的按日期分组文件列表');
        return cached.data;
      }

      console.log('从数据库获取按日期分组的文件列表...');
      const startTime = Date.now();

      // 从数据库按日期分组获取
      const dateGroups = this.db.prepare(`
        SELECT 
          date_dir,
          COUNT(*) as file_count,
          SUM(file_size) as total_size,
          MIN(created_time) as earliest_file,
          MAX(created_time) as latest_file
        FROM files 
        GROUP BY date_dir 
        ORDER BY date_dir DESC
      `).all();

      const result = {};
      
      for (const group of dateGroups) {
        const files = this.db.prepare(`
          SELECT 
            file_name as name,
            file_path as path,
            file_size as size,
            created_time as created,
            title_dir as titleDir,
            relative_path as relativePath,
            video_duration as duration,
            video_width as width,
            video_height as height,
            video_bitrate as bitrate,
            video_orientation as orientation,
            is_video as isVideo
          FROM files 
          WHERE date_dir = ?
          ORDER BY created_time DESC
        `).all(group.date_dir);

        result[group.date_dir] = {
          files: files.map(file => ({
            ...file,
            created: new Date(file.created),
            size: parseInt(file.size),
            duration: file.duration || null,
            width: file.width || null,
            height: file.height || null,
            bitrate: file.bitrate || null,
            orientation: file.orientation || null,
            isVideo: Boolean(file.isVideo)
          })),
          summary: {
            fileCount: group.file_count,
            totalSize: parseInt(group.total_size),
            earliestFile: new Date(group.earliest_file),
            latestFile: new Date(group.latest_file)
          }
        };
      }

      // 更新内存缓存
      this.memoryCache.set(cacheKey, {
        data: result,
        timestamp: Date.now()
      });

      const endTime = Date.now();
      console.log(`按日期分组文件列表获取完成，耗时: ${endTime - startTime}ms`);

      return result;
    } catch (error) {
      console.error('获取按日期分组文件列表失败:', error.message);
      throw new Error('获取按日期分组文件列表失败: ' + error.message);
    }
  }

  // 清理缓存
  clearCache() {
    this.memoryCache.clear();
    console.log('缓存已清理');
  }

  // 强制重新扫描
  async forceScan() {
    console.log('强制执行全量扫描...');
    this.clearCache();
    await this.performFullScan();
  }

  ensureDownloadDir() {
    fsExtra.ensureDirSync(this.downloadDir);
  }

  // 创建按日期和文件名分类的目录结构
  createDownloadPath(title, searchContext = null, url = null, saveAsDirectory = true) {
    // 获取当前日期，格式为 yyyy-MM-dd
    const now = new Date();
    const dateStr = now.getFullYear() + '-' + 
                   String(now.getMonth() + 1).padStart(2, '0') + '-' + 
                   String(now.getDate()).padStart(2, '0');
    
    // 清理文件名，移除不安全的字符，并添加视频ID后缀
    const safeTitle = this.sanitizeFileName(title, url);
    
    // 创建基础日期目录路径
    const datePath = path.join(this.downloadDir, dateStr);
    
    let fullPath;
    
    // 如果是搜索下载模式，创建搜索关键字目录
    if (searchContext && searchContext.searchType === 'keyword' && searchContext.originalQuery) {
      const safeKeyword = this.sanitizeSearchKeyword(searchContext.originalQuery);
      if (saveAsDirectory) {
        // 创建目录路径：downloads/yyyy-MM-dd/搜索关键字/文件名/
        const keywordPath = path.join(datePath, safeKeyword);
        fullPath = path.join(keywordPath, safeTitle);
      } else {
        // 不创建文件同名目录：downloads/yyyy-MM-dd/搜索关键字/
        fullPath = path.join(datePath, safeKeyword);
      }
      
      // 记录搜索关键字与文件的关系
      this.recordSearchRelation(searchContext.originalQuery, safeKeyword, title, fullPath);
    } 
    // 如果是标签搜索，创建标签目录
    else if (searchContext && searchContext.searchType === 'hashtag' && searchContext.hashtag) {
      const safeHashtag = this.sanitizeFileName(searchContext.hashtag, url);
      if (saveAsDirectory) {
        // 创建目录路径：downloads/yyyy-MM-dd/hashtag_标签名/文件名/
        const hashtagPath = path.join(datePath, `hashtag_${safeHashtag}`);
        fullPath = path.join(hashtagPath, safeTitle);
      } else {
        // 不创建文件同名目录：downloads/yyyy-MM-dd/hashtag_标签名/
        fullPath = path.join(datePath, `hashtag_${safeHashtag}`);
      }
    } else {
      if (saveAsDirectory) {
        // 普通下载：downloads/yyyy-MM-dd/文件名/
        fullPath = path.join(datePath, safeTitle);
      } else {
        // 不创建文件同名目录：downloads/yyyy-MM-dd/
        fullPath = datePath;
      }
    }
    
    // 确保目录存在
    fsExtra.ensureDirSync(fullPath);
    
    // 将新目录添加到扫描队列
    this.scanQueue.add(fullPath);
    
    return fullPath;
  }

  // 清理搜索关键字，移除符号但保留可读性
  sanitizeSearchKeyword(keyword) {
    if (!keyword) return 'unknown_search';
    
    // 移除或替换符号，但保留空格的可读性
    return keyword
      .replace(/[<>:"/\\|?*]/g, '')     // 移除不安全字符
      .replace(/[!@#$%^&*()+=\[\]{}|;':",.<>?]/g, '') // 移除标点符号
      .replace(/\s+/g, ' ')             // 规范化空格
      .trim()                           // 移除首尾空格
      .substring(0, 50);                // 限制长度
  }

  // 记录搜索关键字与文件的关系（使用数据库）
  recordSearchRelation(originalKeyword, sanitizedKeyword, videoTitle, filePath) {
    try {
      this.db.prepare(`
        INSERT OR REPLACE INTO search_relations 
        (original_keyword, sanitized_keyword, video_title, file_path, created_time)
        VALUES (?, ?, ?, ?, ?)
      `).run(originalKeyword, sanitizedKeyword, videoTitle, filePath, Date.now());
      
      console.log(`记录搜索关系: "${originalKeyword}" -> "${videoTitle}"`);
    } catch (error) {
      console.error('记录搜索关系失败:', error.message);
    }
  }

  // 获取搜索关系数据（从数据库）
  getSearchRelations() {
    try {
      const relations = this.db.prepare(`
        SELECT 
          original_keyword,
          sanitized_keyword,
          COUNT(*) as file_count,
          MAX(created_time) as latest_download
        FROM search_relations 
        GROUP BY original_keyword, sanitized_keyword
        ORDER BY latest_download DESC
      `).all();

      const result = {};
      for (const relation of relations) {
        const files = this.db.prepare(`
          SELECT video_title, file_path, created_time
          FROM search_relations 
          WHERE original_keyword = ?
          ORDER BY created_time DESC
        `).all(relation.original_keyword);

        result[relation.original_keyword] = {
          sanitizedKeyword: relation.sanitized_keyword,
          files: files.map(file => ({
            title: file.video_title,
            path: file.file_path,
            downloadedAt: new Date(file.created_time).toISOString()
          })),
          createdAt: new Date(relation.latest_download).toISOString()
        };
      }

      return result;
    } catch (error) {
      console.error('读取搜索关系失败:', error.message);
      return {};
    }
  }

  // 从YouTube URL中提取唯一标识符
  extractVideoId(url) {
    try {
      const urlObj = new URL(url);
      
      // 处理标准YouTube URL: https://www.youtube.com/watch?v=VIDEO_ID
      if (urlObj.hostname.includes('youtube.com') && urlObj.pathname === '/watch') {
        const videoId = urlObj.searchParams.get('v');
        if (videoId) return videoId;
      }
      
      // 处理YouTube Shorts URL: https://www.youtube.com/shorts/VIDEO_ID
      if (urlObj.hostname.includes('youtube.com') && urlObj.pathname.startsWith('/shorts/')) {
        const videoId = urlObj.pathname.split('/shorts/')[1];
        if (videoId) return videoId;
      }
      
      // 处理短链接: https://youtu.be/VIDEO_ID
      if (urlObj.hostname === 'youtu.be') {
        const videoId = urlObj.pathname.substring(1); // 移除开头的 '/'
        if (videoId) return videoId;
      }
      
      // 如果无法提取，返回null
      return null;
    } catch (error) {
      console.warn('提取视频ID失败:', error.message);
      return null;
    }
  }

  // 清理文件名，移除不安全的字符，并添加视频ID后缀
  sanitizeFileName(filename, url = null) {
    if (!filename) return 'unknown';
    
    // 清理基础文件名
    let cleanName = filename
      .replace(/[<>:"/\\|?*]/g, '_')  // 替换不安全字符为下划线
      .replace(/\s+/g, '_')          // 替换空格为下划线
      .replace(/_{2,}/g, '_')        // 多个下划线替换为单个
      .replace(/^_+|_+$/g, '')       // 移除开头和结尾的下划线
      .substring(0, 80);             // 限制基础名称长度，为ID留出空间
    
    // 如果提供了URL，尝试提取视频ID并添加为后缀
    if (url) {
      const videoId = this.extractVideoId(url);
      if (videoId) {
        cleanName = `${cleanName}_${videoId}`;
      }
    }
    
    return cleanName || 'unknown';
  }

  // 判断是否为视频文件
  isVideoFile(filename) {
    const videoExtensions = ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v', '.3gp', '.ogv'];
    const extension = path.extname(filename).toLowerCase();
    return videoExtensions.includes(extension);
  }

  // 获取视频文件时长（保持兼容性）
  async getVideoDuration(filePath) {
    return this.getVideoDurationWithTimeout(filePath, 10000);
  }

  // 检查FFmpeg是否可用
  async checkFFmpegAvailable() {
    return new Promise((resolve) => {
      const ffmpeg = spawn('ffmpeg', ['-version']);
      
      ffmpeg.on('error', () => {
        resolve(false);
      });
      
      ffmpeg.on('close', (code) => {
        resolve(code === 0);
      });
    });
  }

  // 下载完成后的清理工作
  onDownloadComplete() {
    // 清理相关缓存
    this.memoryCache.delete('files');
    this.memoryCache.delete('filesByDate');
    this.memoryCache.delete('directoryStructure');
    
    // 触发增量扫描
    setTimeout(() => {
      if (!this.isScanning) {
        this.performIncrementalScan();
      }
    }, 1000);
  }

  // 关闭数据库连接
  close() {
    this.stopBackgroundScan();
    if (this.watchTimer) {
      clearInterval(this.watchTimer);
    }
    if (this.db) {
      this.db.close();
    }
  }

  // 其他方法保持不变...
  async downloadVideo(url, options = {}) {
    // 下载逻辑保持不变，只在最后调用 onDownloadComplete
    // ... 原有的下载逻辑 ...
    
    // 下载完成后清理缓存并触发扫描
    this.onDownloadComplete();
  }

  // 获取目录结构（优化版本）
  async getDirectoryStructure() {
    try {
      // 检查内存缓存
      const cacheKey = 'directoryStructure';
      const cached = this.memoryCache.get(cacheKey);
      if (cached && (Date.now() - cached.timestamp) < this.cacheExpiry) {
        console.log('使用内存缓存的目录结构');
        return cached.data;
      }

      console.log('从数据库构建目录结构...');
      const startTime = Date.now();

      // 从数据库获取目录结构数据
      const structure = this.db.prepare(`
        SELECT 
          date_dir,
          title_dir,
          COUNT(*) as file_count,
          SUM(file_size) as total_size,
          MAX(created_time) as latest_file
        FROM files 
        GROUP BY date_dir, title_dir
        ORDER BY date_dir DESC, title_dir ASC
      `).all();

      // 获取所有文件的详细信息（包含视频和音频文件）
      const allFiles = this.db.prepare(`
        SELECT 
          file_name,
          file_path,
          file_size,
          created_time,
          video_duration,
          date_dir,
          title_dir
        FROM files 
        WHERE file_name LIKE '%.mp4' OR file_name LIKE '%.mkv' OR file_name LIKE '%.avi' OR file_name LIKE '%.mov' OR file_name LIKE '%.webm' 
           OR file_name LIKE '%.mp3' OR file_name LIKE '%.wav' OR file_name LIKE '%.flac' OR file_name LIKE '%.aac' OR file_name LIKE '%.m4a'
        ORDER BY date_dir DESC, title_dir ASC, created_time DESC
      `).all();

      const result = {
        name: path.basename(this.downloadDir),
        type: 'folder',
        path: this.downloadDir,
        children: [],
        totalFiles: 0,
        totalSize: 0
      };

      const dateMap = new Map();

      // 首先构建目录结构
      for (const item of structure) {
        if (!dateMap.has(item.date_dir)) {
          dateMap.set(item.date_dir, {
            name: item.date_dir,
            type: 'folder',
            path: path.join(this.downloadDir, item.date_dir),
            children: [],
            totalFiles: 0,
            totalSize: 0
          });
        }

        const dateNode = dateMap.get(item.date_dir);
        const titleNode = {
          name: item.title_dir,
          type: 'folder',
          path: path.join(this.downloadDir, item.date_dir, item.title_dir),
          children: [],
          totalFiles: item.file_count,
          totalSize: parseInt(item.total_size),
          latestFile: new Date(item.latest_file)
        };

        dateNode.children.push(titleNode);
        dateNode.totalFiles += item.file_count;
        dateNode.totalSize += parseInt(item.total_size);
      }

      // 然后添加文件到相应的目录
      for (const file of allFiles) {
        const dateNode = dateMap.get(file.date_dir);
        if (dateNode) {
          const titleNode = dateNode.children.find(child => child.name === file.title_dir);
          if (titleNode) {
            // 判断文件类型
            const fileExt = file.file_name.split('.').pop().toLowerCase();
            const isVideo = ['mp4', 'mkv', 'avi', 'mov', 'webm', 'flv', 'm4v'].includes(fileExt);
            const isAudio = ['mp3', 'wav', 'flac', 'aac', 'm4a', 'ogg'].includes(fileExt);
            
            titleNode.children.push({
              name: file.file_name,
              type: 'file',
              path: file.file_path,
              size: parseInt(file.file_size),
              created: new Date(file.created_time),
              duration: file.video_duration,
              isVideo: isVideo,
              isAudio: isAudio,
              fileType: isVideo ? 'video' : (isAudio ? 'audio' : 'other')
            });
          }
        }
      }

      result.children = Array.from(dateMap.values());
      
      // 计算总统计
      result.totalFiles = allFiles.length;
      result.totalSize = result.children.reduce((sum, dateNode) => sum + dateNode.totalSize, 0);

      // 更新内存缓存
      this.memoryCache.set(cacheKey, {
        data: result,
        timestamp: Date.now()
      });

      const endTime = Date.now();
      console.log(`目录结构构建完成，耗时: ${endTime - startTime}ms，包含 ${result.totalFiles} 个文件`);

      return result;
    } catch (error) {
      console.error('获取目录结构失败:', error.message);
      throw new Error('获取目录结构失败: ' + error.message);
    }
  }

  // 获取扫描统计信息
  async getScanStats() {
    try {
      // 获取文件统计
      const fileStats = this.db.prepare(`
        SELECT 
          COUNT(*) as total_files,
          SUM(file_size) as total_size,
          COUNT(CASE WHEN video_duration > 0 THEN 1 END) as video_files,
          AVG(video_duration) as avg_duration,
          MIN(created_time) as oldest_file,
          MAX(created_time) as newest_file
        FROM files
      `).get();

      // 获取扫描历史统计
      const scanStats = this.db.prepare(`
        SELECT 
          COUNT(*) as total_scans,
          COUNT(CASE WHEN scan_type = 'full' THEN 1 END) as full_scans,
          COUNT(CASE WHEN scan_type = 'incremental' THEN 1 END) as incremental_scans,
          AVG(duration_ms) as avg_scan_duration,
          MAX(end_time) as last_scan_time,
          SUM(files_added) as total_files_added,
          SUM(files_updated) as total_files_updated,
          SUM(files_removed) as total_files_removed
        FROM scan_history 
        WHERE end_time IS NOT NULL
      `).get();

      // 获取最近的扫描记录
      const recentScans = this.db.prepare(`
        SELECT 
          scan_type,
          start_time,
          end_time,
          duration_ms,
          files_added,
          files_updated,
          files_removed,
          error_message
        FROM scan_history 
        ORDER BY start_time DESC 
        LIMIT 10
      `).all();

      // 获取目录统计
      const dirStats = this.db.prepare(`
        SELECT 
          COUNT(DISTINCT date_dir) as date_directories,
          COUNT(DISTINCT title_dir) as title_directories
        FROM files
      `).get();

      return {
        files: {
          totalFiles: fileStats.total_files || 0,
          totalSize: fileStats.total_size || 0,
          videoFiles: fileStats.video_files || 0,
          avgDuration: fileStats.avg_duration || 0,
          oldestFile: fileStats.oldest_file,
          newestFile: fileStats.newest_file
        },
        scans: {
          totalScans: scanStats.total_scans || 0,
          fullScans: scanStats.full_scans || 0,
          incrementalScans: scanStats.incremental_scans || 0,
          avgScanDuration: scanStats.avg_scan_duration || 0,
          lastScanTime: scanStats.last_scan_time,
          totalFilesAdded: scanStats.total_files_added || 0,
          totalFilesUpdated: scanStats.total_files_updated || 0,
          totalFilesRemoved: scanStats.total_files_removed || 0
        },
        directories: {
          dateDirectories: dirStats.date_directories || 0,
          titleDirectories: dirStats.title_directories || 0
        },
        recentScans: recentScans.map(scan => ({
          ...scan,
          startTime: new Date(scan.start_time),
          endTime: scan.end_time ? new Date(scan.end_time) : null,
          duration: scan.duration_ms ? `${scan.duration_ms}ms` : null
        })),
        currentStatus: {
          isScanning: this.isScanning,
          scanQueueSize: this.scanQueue.size,
          backgroundScanEnabled: !!this.backgroundScanTimer
        }
      };
    } catch (error) {
      console.error('获取扫描统计失败:', error.message);
      throw new Error('获取扫描统计失败: ' + error.message);
    }
  }

  // 获取扫描状态
  getScanStatus() {
    return {
      isScanning: this.isScanning,
      scanQueueSize: this.scanQueue.size,
      backgroundScanEnabled: !!this.backgroundScanTimer,
      fullScanInterval: this.fullScanInterval,
      incrementalScanInterval: this.incrementalScanInterval,
      lastScanTime: this.lastScanTime,
      currentScanType: this.currentScanType || null,
      scanStartTime: this.scanStartTime || null
    };
  }

  // 清理数据库中不存在的文件记录
  async cleanupDatabase() {
    try {
      console.log('开始清理数据库中不存在的文件记录...');
      const startTime = Date.now();

      // 获取所有文件记录
      const allFiles = this.db.prepare('SELECT id, file_path FROM files').all();
      
      let removedCount = 0;
      const removedFiles = [];

      // 检查每个文件是否存在
      for (const file of allFiles) {
        if (!fs.existsSync(file.file_path)) {
          // 删除不存在的文件记录
          this.db.prepare('DELETE FROM files WHERE id = ?').run(file.id);
          removedCount++;
          removedFiles.push(file.file_path);
          
          if (removedFiles.length <= 10) { // 只记录前10个被删除的文件路径
            console.log(`删除不存在的文件记录: ${file.file_path}`);
          }
        }
      }

      // 清理搜索关系中的无效文件
      const searchRelations = this.db.prepare('SELECT * FROM search_relations').all();
      let cleanedRelations = 0;

      for (const relation of searchRelations) {
        const files = JSON.parse(relation.files);
        const validFiles = files.filter(file => fs.existsSync(file.path));
        
        if (validFiles.length !== files.length) {
          if (validFiles.length === 0) {
            // 如果没有有效文件，删除整个关系记录
            this.db.prepare('DELETE FROM search_relations WHERE id = ?').run(relation.id);
          } else {
            // 更新关系记录，只保留有效文件
            this.db.prepare('UPDATE search_relations SET files = ? WHERE id = ?')
              .run(JSON.stringify(validFiles), relation.id);
          }
          cleanedRelations++;
        }
      }

      // 清理内存缓存
      this.clearCache();

      const endTime = Date.now();
      const duration = endTime - startTime;

      console.log(`数据库清理完成，耗时: ${duration}ms`);
      console.log(`删除了 ${removedCount} 个不存在的文件记录`);
      console.log(`清理了 ${cleanedRelations} 个搜索关系记录`);

      return {
        removedFilesCount: removedCount,
        cleanedRelationsCount: cleanedRelations,
        duration: duration,
        removedFiles: removedFiles.slice(0, 10), // 只返回前10个被删除的文件路径
        totalChecked: allFiles.length
      };
    } catch (error) {
      console.error('清理数据库失败:', error.message);
      throw new Error('清理数据库失败: ' + error.message);
    }
  }

  // 获取视频信息
  async getVideoInfo(url, playlist = false) {
    try {
      const { spawn } = require('child_process');
      
      // 构建 yt-dlp 参数
      const args = [
        url,
        '--dump-json',
        '--no-download'
      ];
      
      // 添加网络重试和超时配置
      args.push('--retries', '10');           // 重试次数
      args.push('--fragment-retries', '10');  // 片段重试次数
      args.push('--socket-timeout', '30');    // Socket超时时间(秒)
      args.push('--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
      args.push('--sleep-requests', '1');     // 请求间隔时间(秒)
      
      // 添加更多网络优化参数
      args.push('--http-chunk-size', '10M');  // HTTP块大小，减少网络请求次数
      args.push('--hls-prefer-native');       // 优先使用原生HLS下载器
      args.push('--abort-on-unavailable-fragment'); // 不因单个片段失败而终止下载
      args.push('--extractor-args', 'youtube:player_client=web;formats=missing_pot'); // 使用web客户端并启用缺少PO Token的格式
      args.push('--no-check-formats');        // 跳过格式检查，提高稳定性
      
      // 如果是播放列表，添加播放列表参数
      if (playlist) {
        args.push('--yes-playlist');
      } else {
        args.push('--no-playlist');
      }

      return new Promise((resolve, reject) => {
        const ytdlp = spawn('yt-dlp', args);
        let output = '';
        let error = '';

        ytdlp.stdout.on('data', (data) => {
          output += data.toString();
        });

        ytdlp.stderr.on('data', (data) => {
          error += data.toString();
        });

        ytdlp.on('close', (code) => {
          if (code === 0) {
            try {
              // 解析 JSON 输出
              const lines = output.trim().split('\n');
              const videoInfo = JSON.parse(lines[0]); // 第一行是主要视频信息
              
              // 返回简化的视频信息
              resolve({
                title: videoInfo.title || 'Unknown Title',
                description: videoInfo.description || '',
                duration: videoInfo.duration || 0,
                uploader: videoInfo.uploader || 'Unknown',
                upload_date: videoInfo.upload_date || '',
                view_count: videoInfo.view_count || 0,
                like_count: videoInfo.like_count || 0,
                thumbnail: videoInfo.thumbnail || '',
                webpage_url: videoInfo.webpage_url || url,
                id: videoInfo.id || '',
                extractor: videoInfo.extractor || 'youtube'
              });
            } catch (parseError) {
              console.error('解析视频信息失败:', parseError.message);
              reject(new Error('解析视频信息失败: ' + parseError.message));
            }
          } else {
            // 智能错误分类和处理
            const errorTypes = {
              networkError: error.includes('handshake operation timed out') ||
                           error.includes('远程主机强迫关闭了一个现有的连接') ||
                           error.includes('WinError 10054') ||
                           error.includes('SSL') ||
                           error.includes('timeout'),
              fragmentError: error.includes('fragment') && error.includes('not found'),
              poTokenError: error.includes('PO Token') || error.includes('po token') || error.includes('HTTP Error 403'),
              sabrError: error.includes('SABR streaming') || error.includes('Some web client https formats have been skipped'),
              formatError: error.includes('No video formats found') || error.includes('Requested format is not available'),
              geoError: error.includes('not available in your country') || error.includes('geo-blocked'),
              privateError: error.includes('Private video') || error.includes('This video is private')
            };
            
            let errorMessage = '获取视频信息失败: ' + error;
            
            if (errorTypes.networkError) {
              console.error('网络连接错误，已配置自动重试机制:', error);
              errorMessage = '网络连接不稳定，请稍后重试。如果问题持续存在，请检查网络连接。';
            } else if (errorTypes.fragmentError) {
              console.error('视频片段获取失败:', error);
              errorMessage = '视频片段获取失败，请稍后重试或尝试其他视频。';
            } else if (errorTypes.poTokenError) {
              console.error('PO Token验证失败，已配置missing_pot参数:', error);
              errorMessage = 'YouTube验证失败，已使用备用配置重试。如果问题持续，请稍后再试。';
            } else if (errorTypes.sabrError) {
              console.error('SABR格式问题，已配置web客户端:', error);
              errorMessage = '视频格式获取失败，已使用web客户端配置重试。';
            } else if (errorTypes.formatError) {
              console.error('视频格式不可用:', error);
              errorMessage = '当前视频格式不可用，请尝试其他质量选项。';
            } else if (errorTypes.geoError) {
              console.error('地理位置限制:', error);
              errorMessage = '该视频在当前地区不可用（地理限制）。';
            } else if (errorTypes.privateError) {
              console.error('私有视频:', error);
              errorMessage = '该视频为私有视频或已被删除，无法访问。';
            } else {
              console.error('获取视频信息失败:', error);
            }
            
            reject(new Error(errorMessage));
          }
        });

        ytdlp.on('error', (err) => {
          console.error('yt-dlp 执行失败:', err.message);
          reject(new Error('yt-dlp 执行失败: ' + err.message));
        });
      });
    } catch (error) {
      console.error('getVideoInfo 方法执行失败:', error.message);
      throw new Error('getVideoInfo 方法执行失败: ' + error.message);
    }
  }

  // 检查并删除重复文件（基于视频ID的智能重复检查）
  async removeExistingFiles(downloadPath, url) {
    try {
      const videoId = this.extractVideoId(url);
      if (!videoId) {
        console.log('无法提取视频ID，跳过重复文件检查');
        return;
      }

      // 在数据库中查找具有相同视频ID的文件
      const existingFiles = this.db.prepare(`
        SELECT file_path, file_name 
        FROM files 
        WHERE file_name LIKE '%_${videoId}.%' OR file_path LIKE '%_${videoId}.%'
      `).all();

      if (existingFiles.length === 0) {
        console.log('未找到重复文件');
        return;
      }

      console.log(`找到 ${existingFiles.length} 个可能的重复文件`);
      
      const fs = require('fs-extra');
      let removedCount = 0;

      for (const file of existingFiles) {
        try {
          // 检查文件是否实际存在
          if (await fs.pathExists(file.file_path)) {
            await fs.remove(file.file_path);
            console.log(`删除重复文件: ${file.file_path}`);
            removedCount++;
          }
          
          // 从数据库中删除记录
          this.db.prepare('DELETE FROM files WHERE file_path = ?').run(file.file_path);
        } catch (error) {
          console.error(`删除文件失败 ${file.file_path}:`, error.message);
        }
      }

      if (removedCount > 0) {
        console.log(`成功删除 ${removedCount} 个重复文件`);
        // 清理缓存
        this.memoryCache.delete('files');
        this.memoryCache.delete('filesByDate');
        this.memoryCache.delete('directoryStructure');
      }

    } catch (error) {
      console.error('删除重复文件时发生错误:', error.message);
      // 不抛出错误，允许下载继续进行
    }
  }

  // 检查 yt-dlp 是否可用
  async checkYtDlp() {
    try {
      const { exec } = require('child_process');
      const { promisify } = require('util');
      const execAsync = promisify(exec);

      // 尝试执行 yt-dlp --version 命令
      await execAsync('yt-dlp --version');
      return true;
    } catch (error) {
      console.warn('yt-dlp 不可用:', error.message);
      return false;
    }
  }
}

module.exports = YouTubeDownloader;